BPF-eBPF 开发路线一:BCC 入门、工具使用与自定义脚本

你若想得到这世界上最好的东西,先得让世界看到最好的你。——毛姆

写在前面


  • 这一篇专门整理 BCC 路线,重点贴近 iovisor/bcc 仓库的 README、工具清单和常见使用方式
  • 它最适合 eBPF 初学者、性能分析人员和临时排障场景
  • 学 BCC 的重点不是把工具名背下来,而是理解一个工具为什么选择这个挂点、为什么输出这种数据

你若想得到这世界上最好的东西,先得让世界看到最好的你。——毛姆


系列导航

  1. BPF-eBPF 学习总览:从概念、机制到工具链选择
  2. BPF-eBPF 实战入门:环境准备、最小实验与排错思路
  3. BPF-eBPF 开发路线一:BCC 入门、工具使用与自定义脚本
  4. BPF-eBPF 开发路线二:libbpf、CO-RE 与 libbpf-bootstrap 实战
  5. BPF-eBPF 开发路线三:ebpf-go、bpf2go 与 Go 工程集成

BCC 到底是什么

BCC 全称通常写作 BPF Compiler Collection。按照官方仓库的定位,它既是一个 eBPF 工具集,也是一个便于开发 eBPF 程序的框架。

它常见的特点是:

  • 内核态逻辑一般用 C
  • 用户态控制通常用 PythonLua
  • 仓库里自带大量现成工具
  • 很适合做 tracing、profiling、故障排查和临时分析

这也是为什么很多人第一眼接触 eBPF,看到的就是 execsnoopopensnoopbiolatencyrunqlat 这些 BCC 工具。

为什么 BCC 适合入门

BCC 的优势很明显:

  • 现成工具多
  • 学习反馈快
  • 对“观测问题”的建模很直观
  • 你可以先运行,再看代码,再修改

如果你现在还说不清:

  • 为什么某个问题该挂 kprobe
  • 为什么有些场景适合输出事件流
  • 为什么有些场景适合输出直方图

那先学 BCC 往往比先啃底层装载细节更有效。

官方仓库里有什么

https://github.com/iovisor/bcc 仓库里,最值得新手先看的几个目录是:

  • tools/
  • examples/
  • libbpf-tools/
  • docs/
  • man/

阅读顺序建议:

  1. 先看 README
  2. 再看 tools/ 里的现成工具
  3. 挑自己最关心的领域,看对应脚本和帮助文档
  4. 最后再去看 examples

建议先跑哪些 BCC 工具

进程与系统调用

1
2
3
sudo execsnoop
sudo opensnoop
sudo statsnoop

适合建立的直觉:

  • 进程什么时候执行
  • 文件什么时候被打开
  • 系统调用事件如何被流式输出

CPU 与调度

1
2
3
sudo runqlat
sudo offcputime
sudo profile

适合建立的直觉:

  • 延迟不是只看平均值
  • 调度等待和 off-CPU 时间常常比单纯 CPU 使用率更有价值

存储与 IO

1
2
3
sudo biolatency
sudo biosnoop
sudo biotop

适合建立的直觉:

  • 既可以看单事件,也可以看分布
  • 设备慢和应用慢之间,往往要靠这类工具去下钻

网络

1
2
3
sudo tcpconnect
sudo tcplife
sudo tcpretrans

适合建立的直觉:

  • 网络观测不只看抓包
  • eBPF 很擅长把连接生命周期和内核路径数据串起来

一个很重要的学习方法:先看输出,再猜实现

execsnoop 为例,先不要急着看代码,先观察它输出什么:

  • 时间
  • PID
  • 进程名
  • 命令参数

然后再反推它的设计:

  • 挂点可能和 execve 有关
  • 输出是事件流,不是累计直方图
  • 需要从内核态把字符串参数送到用户态

这种“先看结果,再拆实现”的方法,对学 BCC 非常有效。

BCC 工具的典型结构

一个典型的 BCC 脚本通常分为两部分:

  1. C 字符串里的 eBPF 程序
  2. Python 控制逻辑

大致结构类似:

1
2
3
4
5
6
7
8
9
10
11
12
from bcc import BPF

program = r"""
int hello(void *ctx) {
bpf_trace_printk("hello\\n");
return 0;
}
"""

b = BPF(text=program)
b.attach_kprobe(event="do_sys_open", fn_name="hello")
b.trace_print()

这个例子很小,但已经把 BCC 的核心风格体现出来了:

  • 用 Python 写控制面
  • 用 BCC 帮你完成编译、加载和 attach
  • 用 C 写真正跑在内核态的逻辑

学 BCC 时重点理解哪些能力

1. attach 到哪里

你至少要熟悉:

  • kprobe/kretprobe
  • tracepoint
  • uprobe/uretprobe
  • USDT

2. 数据怎么回到用户态

常见方式包括:

  • trace_printk
  • perf buffer
  • map 统计

3. 数据为什么这样聚合

这点很关键。比如:

  • 看单次事件,常用事件流
  • 看分布,常用 histogram
  • 看总量排行,常用 top 风格输出

你如果只学“命令怎么敲”,不学“为什么要这样聚合”,BCC 就很难真正吃透。

一个适合新手的自定义脚本练习

下面给一个非常适合练手的方向:统计某个内核函数被调用了多少次。

思路:

  1. 选择一个稳定、容易触发的函数
  2. attach_kprobe
  3. 每次调用对 map 计数
  4. 用户态定时读取并打印

这种练手题的价值在于:

  • 你会接触 attach
  • 会接触 map
  • 会接触内核态和用户态交互
  • 不需要一开始就处理复杂结构体

BCC 的优势与边界

优势

  • 学习曲线相对平缓
  • 原型验证非常快
  • 很适合线上临时分析
  • 工具库成熟,经验材料多

边界

  • 依赖目标机环境较多
  • 更适合快速分析,不是所有场景都适合长期工程化交付
  • 如果以后要做 CO-RE、做跨内核兼容、做更标准的生产应用,还是要进一步学习 libbpf

所以更准确地说:

  • BCC 适合“先会用”
  • libbpf 适合“真正学透”

我建议的 BCC 学习顺序

  1. 先跑 10 个现成工具
  2. 记录每个工具的观测目标、挂点和输出形式
  3. 选 1 个工具精读源码
  4. 改 1 个输出字段
  5. 自己写 1 个最小脚本

做到这一步,你对 eBPF 的理解会明显比“只读概念文档”深很多。

最后总结

学习 BCC,真正有价值的不是“我会用多少条命令”,而是:

  • 我能不能从一个问题反推出应该观察什么事件
  • 我能不能判断应该选事件流、直方图还是排行输出
  • 我能不能把一个现成工具改成更适合自己场景的脚本

如果这三件事做到了,BCC 这条线就算真正入门了。

博文部分内容参考

© 文中涉及参考链接内容版权归原作者所有,如有侵权请告知 :)



© 2018-至今 liruilonger@gmail.com, 保持署名-非商用-相同方式共享(CC BY-NC-SA 4.0)

发布于

2026-04-14

更新于

2026-04-14

许可协议

评论
加载中,最新评论有1分钟缓存...
Your browser is out-of-date!

Update your browser to view this website correctly.&npsb;Update my browser now

×